package com.fy.fyspace.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fy.fyspace.mapper.PictureHotnessMapper;
import com.fy.fyspace.mapper.PictureMapper;
import com.fy.fyspace.model.entity.Picture;
import com.fy.fyspace.model.entity.PictureHotness;
import com.fy.fyspace.service.PictureHotnessService;
import com.fy.fyspace.service.hotness.strategy.HotnessCalculationStrategy;
import com.fy.fyspace.service.hotness.strategy.HotnessStrategyFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 图片热度Service实现类
 * 设计模式：服务层实现模式
 * 作用：实现图片热度相关的业务逻辑
 * 
 * @author fwq
 * @since 2024-12-19
 */
@Slf4j
@Service
public class PictureHotnessServiceImpl implements PictureHotnessService {
    
    @Autowired
    private PictureHotnessMapper pictureHotnessMapper;
    
    @Autowired
    private PictureMapper pictureMapper;
    
    @Autowired
    private HotnessStrategyFactory strategyFactory;
    
    @Override
    @Transactional
    public PictureHotness calculateHotness(Long pictureId, String strategyName) {
        log.info("开始计算单张图片热度，图片ID: {}, 策略: {}", pictureId, strategyName);
        
        // 查询图片信息
        Picture picture = pictureMapper.selectById(pictureId);
        if (picture == null) {
            log.warn("图片不存在，图片ID: {}", pictureId);
            return null;
        }
        
        // 获取计算策略
        HotnessCalculationStrategy strategy = strategyFactory.getStrategy(strategyName);
        
        // 创建计算DTO
        var calculationDTO = createCalculationDTO(picture, new Date());
        
        // 执行计算
        var score = strategy.calculateHotness(calculationDTO);
        
        // 创建热度实体
        PictureHotness hotness = createPictureHotness(picture, score, new Date());
        
        // 保存或更新热度数据
        saveOrUpdate(hotness);
        
        log.info("单张图片热度计算完成，图片ID: {}, 分数: {}", pictureId, hotness.getCurrentScore());
        return hotness;
    }
    
    @Override
    @Transactional
    public List<PictureHotness> batchCalculateHotness(List<Long> pictureIds, String strategyName) {
        log.info("开始批量计算图片热度，图片数量: {}, 策略: {}", pictureIds.size(), strategyName);
        
        if (pictureIds.isEmpty()) {
            return new ArrayList<>();
        }
        
        // 查询图片信息
        List<Picture> pictures = pictureMapper.selectBatchIds(pictureIds);
        if (pictures.isEmpty()) {
            log.warn("未找到任何图片信息");
            return new ArrayList<>();
        }
        
        // 获取计算策略
        HotnessCalculationStrategy strategy = strategyFactory.getStrategy(strategyName);
        
        List<PictureHotness> results = new ArrayList<>();
        Date calculateTime = new Date();
        
        for (Picture picture : pictures) {
            try {
                // 创建计算DTO
                var calculationDTO = createCalculationDTO(picture, calculateTime);
                
                // 执行计算
                var score = strategy.calculateHotness(calculationDTO);
                
                // 创建热度实体
                PictureHotness hotness = createPictureHotness(picture, score, calculateTime);
                results.add(hotness);
                
                log.debug("图片ID: {} 热度计算完成，分数: {}", picture.getId(), score);
                
            } catch (Exception e) {
                log.error("计算图片热度失败，图片ID: {}", picture.getId(), e);
                // 继续处理其他图片，不中断整个流程
            }
        }
        
        // 批量保存或更新热度数据
        if (!results.isEmpty()) {
            batchSaveOrUpdate(results);
        }
        
        log.info("批量热度计算完成，成功计算数量: {}/{}", results.size(), pictureIds.size());
        return results;
    }
    
    @Override
    @Transactional
    public List<PictureHotness> calculateAllHotness(String strategyName) {
        log.info("开始计算所有图片热度，策略: {}", strategyName);
        
        // 获取所有图片
        List<Picture> pictures = pictureMapper.selectList(null);
        if (pictures.isEmpty()) {
            log.warn("没有找到图片数据");
            return new ArrayList<>();
        }
        
        log.info("找到图片数量: {}", pictures.size());
        
        // 获取计算策略
        HotnessCalculationStrategy strategy = strategyFactory.getStrategy(strategyName);
        if (strategy == null) {
            log.error("未找到策略: {}", strategyName);
            return new ArrayList<>();
        }
        
        log.info("使用策略: {}", strategy.getStrategyName());
        
        List<PictureHotness> results = new ArrayList<>();
        Date calculateTime = new Date();
        
        for (Picture picture : pictures) {
            try {
                log.debug("开始计算图片热度，图片ID: {}", picture.getId());
                
                // 创建计算DTO
                var calculationDTO = createCalculationDTO(picture, calculateTime);
                
                // 验证DTO数据
                if (calculationDTO.getPictureId() == null) {
                    log.warn("图片ID为空，跳过计算，图片: {}", picture);
                    continue;
                }
                
                log.debug("计算DTO创建完成，图片ID: {}, 下载数: {}, 点赞数: {}, 收藏数: {}, 创建时间: {}", 
                    calculationDTO.getPictureId(), 
                    calculationDTO.getDownloadCount(), 
                    calculationDTO.getLikeCount(), 
                    calculationDTO.getFavoriteCount(), 
                    calculationDTO.getCreateTime());
                
                // 执行计算
                var score = strategy.calculateHotness(calculationDTO);
                
                log.debug("热度计算完成，图片ID: {}, 分数: {}", picture.getId(), score);
                
                // 创建热度实体
                PictureHotness hotness = createPictureHotness(picture, score, calculateTime);
                results.add(hotness);
                
                log.debug("图片ID: {} 热度计算完成，分数: {}", picture.getId(), score);
                
            } catch (Exception e) {
                log.error("计算图片热度失败，图片ID: {}, 错误详情: {}", picture.getId(), e.getMessage(), e);
                // 继续处理其他图片，不中断整个流程
            }
        }
        
        // 批量保存或更新热度数据
        if (!results.isEmpty()) {
            batchSaveOrUpdate(results);
        }
        
        log.info("所有图片热度计算完成，成功计算数量: {}/{}", results.size(), pictures.size());
        return results;
    }
    
    @Override
    @Transactional
    public boolean updateHistoricalScores(Long pictureId) {
        log.info("开始更新图片历史分数，图片ID: {}", pictureId);
        
        try {
            // 获取当前热度数据
            PictureHotness currentHotness = getByPictureId(pictureId);
            if (currentHotness == null) {
                log.warn("图片热度数据不存在，图片ID: {}", pictureId);
                return false;
            }
            
            // 更新历史分数（这里简化处理，实际应该根据具体时间范围计算）
            // 昨日分数 = 当前分数 * 0.95
            // 上周分数 = 当前分数 * 0.85
            // 上月分数 = 当前分数 * 0.70
            
            var yesterdayScore = currentHotness.getCurrentScore().multiply(new java.math.BigDecimal("0.95"));
            var lastWeekScore = currentHotness.getCurrentScore().multiply(new java.math.BigDecimal("0.85"));
            var lastMonthScore = currentHotness.getCurrentScore().multiply(new java.math.BigDecimal("0.70"));
            
            // 更新数据库
            int result = pictureHotnessMapper.updateHistoricalScores(pictureId, yesterdayScore, lastWeekScore, lastMonthScore);
            
            log.info("图片历史分数更新完成，图片ID: {}, 结果: {}", pictureId, result > 0);
            return result > 0;
            
        } catch (Exception e) {
            log.error("更新图片历史分数失败，图片ID: {}", pictureId, e);
            return false;
        }
    }
    
    @Override
    @Transactional
    public int batchUpdateHistoricalScores(List<Long> pictureIds) {
        log.info("开始批量更新图片历史分数，图片数量: {}", pictureIds.size());
        
        int successCount = 0;
        for (Long pictureId : pictureIds) {
            if (updateHistoricalScores(pictureId)) {
                successCount++;
            }
        }
        
        log.info("批量更新历史分数完成，成功数量: {}/{}", successCount, pictureIds.size());
        return successCount;
    }
    
    @Override
    public PictureHotness getByPictureId(Long pictureId) {
        LambdaQueryWrapper<PictureHotness> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(PictureHotness::getPictureId, pictureId);
        return pictureHotnessMapper.selectOne(wrapper);
    }
    
    @Override
    public List<PictureHotness> getByPictureIds(List<Long> pictureIds) {
        if (pictureIds.isEmpty()) {
            return new ArrayList<>();
        }
        return pictureHotnessMapper.selectByPictureIds(pictureIds);
    }
    
    @Override
    @Transactional
    public boolean saveOrUpdate(PictureHotness pictureHotness) {
        try {
            // 检查是否已存在
            PictureHotness existing = getByPictureId(pictureHotness.getPictureId());
            
            if (existing != null) {
                // 更新
                pictureHotness.setId(existing.getId());
                pictureHotness.setUpdateTime(new Date());
                int result = pictureHotnessMapper.updateById(pictureHotness);
                return result > 0;
            } else {
                // 新增
                pictureHotness.setCreateTime(new Date());
                pictureHotness.setUpdateTime(new Date());
                int result = pictureHotnessMapper.insert(pictureHotness);
                return result > 0;
            }
        } catch (Exception e) {
            log.error("保存或更新热度数据失败，图片ID: {}", pictureHotness.getPictureId(), e);
            return false;
        }
    }
    
    @Override
    @Transactional
    public int batchSaveOrUpdate(List<PictureHotness> hotnessList) {
        if (hotnessList.isEmpty()) {
            return 0;
        }
        
        try {
            int result = pictureHotnessMapper.batchInsertOrUpdate(hotnessList);
            log.info("批量保存或更新热度数据完成，成功数量: {}/{}", result, hotnessList.size());
            return result;
        } catch (Exception e) {
            log.error("批量保存或更新热度数据失败", e);
            return 0;
        }
    }
    
    /**
     * 创建计算DTO
     */
    private com.fy.fyspace.model.dto.hotness.HotnessCalculationDTO createCalculationDTO(Picture picture, Date calculateTime) {
        var dto = new com.fy.fyspace.model.dto.hotness.HotnessCalculationDTO();
        dto.setPictureId(picture.getId());
        dto.setDownloadCount(0); // 注意：当前Picture实体中没有downloadCount字段，暂时设为0
        dto.setLikeCount(picture.getLikeCount() != null ? picture.getLikeCount() : 0);
        dto.setFavoriteCount(picture.getFavoriteCount() != null ? picture.getFavoriteCount() : 0);
        dto.setCreateTime(picture.getCreateTime() != null ? picture.getCreateTime() : new Date()); // 添加空值检查
        dto.setCalculateTime(calculateTime);
        return dto;
    }
    
    /**
     * 创建热度实体
     */
    private PictureHotness createPictureHotness(Picture picture, java.math.BigDecimal score, Date calculateTime) {
        var hotness = new PictureHotness();
        hotness.setPictureId(picture.getId());
        hotness.setCurrentScore(score);
        hotness.setDownloadCount(0); // 注意：当前Picture实体中没有downloadCount字段，暂时设为0
        hotness.setLikeCount(picture.getLikeCount() != null ? picture.getLikeCount() : 0);
        hotness.setFavoriteCount(picture.getFavoriteCount() != null ? picture.getFavoriteCount() : 0);
        hotness.setLastCalculateTime(calculateTime);
        return hotness;
    }
} 